#pragma once

#include "t2sdk_interface.h"
#include "fmt/format.h"
#include "HsCallback.h"
#include "HsFutuSystemInfo.h"

// #include <bits/stdc++.h>

#include <memory>
#include <string>
#include <vector>

using namespace std;

CConfigInterface *s_Configer = nullptr;

CConfigInterface *GetConfiger()
{
	if (s_Configer != nullptr)
		return s_Configer;

	CConfigInterface *lpConfig = NewConfig();
	if (lpConfig == nullptr)
		return nullptr;

	lpConfig->AddRef();
	// [t2sdk] servers指定需要连接的IP地址及端口
	lpConfig->SetString("t2sdk", "servers", "183.129.145.246:7221");

	// [t2sdk] license_file指定许可证文件
	lpConfig->SetString("t2sdk", "license_file", "license.dat");

	// [t2sdk] send_queue_size指定T2_SDK的发送队列大小
	lpConfig->SetString("t2sdk", "send_queue_size", "100");
	// 在此设置一下就可以支持自动重连
	lpConfig->SetString("t2sdk", "auto_reconnect", "1");

	s_Configer = lpConfig;
	return s_Configer;
}

class Request;
class Connection
{
	friend class Request;
	static constexpr int PackerVersion = 2;
	static constexpr int ConnectTimeOut = 1000; // ms

public:
	Connection()
	{
		Create();
	}

	void Create()
	{
		if (GetConfiger() == nullptr)
		{
			throw std::runtime_error("[汇点]恒生创建配置器失败");
		}

		m_Connection = NewConnection(GetConfiger());
		if (m_Connection == nullptr)
		{
			throw std::runtime_error("[汇点]恒生创建连接器失败");
		}
		m_Connection->AddRef();

		int ret = m_Connection->Create2BizMsg(&Connection::m_Callback);
		if (ret != 0)
		{
			throw std::runtime_error(m_Connection->GetErrorMsg(ret));
		}

		ret = m_Connection->Connect(ConnectTimeOut);
		if (ret != 0)
		{
			throw std::runtime_error(m_Connection->GetErrorMsg(ret));
		}

		m_Packer = NewPacker(PackerVersion);
		if (m_Packer == nullptr)
		{
			throw std::runtime_error("[汇点]恒生创建打包器失败");
		}

		// 为打包器增加引用计数，每个打包器调用一次
		m_Packer->AddRef();

		m_BizMsg = NewBizMessage();
		if (m_BizMsg == nullptr)
		{
			throw std::runtime_error("[汇点]恒生构造业务消息失败");
		}
		m_BizMsg->AddRef();
	}

	~Connection()
	{
		// 如果使用SetBuffer自己管理打包器的缓存空间，就不需要调用 FreeMem
		m_Packer->FreeMem(m_Packer->GetPackBuf());
		m_Packer->Release();

		m_BizMsg->Release();

		m_Connection->Release();
		GetConfiger()->Release();
	}

	CConnectionInterface *T2Connection()
	{
		return m_Connection;
	}

private:
	CConfigInterface *GenerateConfiger()
	{
		CConfigInterface *lpConfig = NewConfig();
		if (lpConfig == nullptr)
			return nullptr;

		lpConfig->AddRef();
		// [t2sdk] servers指定需要连接的IP地址及端口
		lpConfig->SetString("t2sdk", "servers", "183.129.145.246:7221");

		// [t2sdk] license_file指定许可证文件
		lpConfig->SetString("t2sdk", "license_file", "license.dat");

		// [t2sdk] send_queue_size指定T2_SDK的发送队列大小
		lpConfig->SetString("t2sdk", "send_queue_size", "100");
		// 在此设置一下就可以支持自动重连
		lpConfig->SetString("t2sdk", "auto_reconnect", "1");

		return lpConfig;
	}

private:
	// 连接对象
	CConnectionInterface *m_Connection = nullptr;
	// 打包器
	IF2Packer *m_Packer = nullptr;

	inline static CCallback m_Callback;

	IBizMessage *m_BizMsg = nullptr;
};

/*管理功能、入参、出参、日志打印等
 */
class Request
{
	using HsRequestParam = std::pair<std::string, std::string>;

public:
	Request(Connection *pConn)
	{
		m_Conn = pConn;
	}

	~Request()
	{
	}

	void Prepare(int funcid)
	{
		m_FuncId = funcid;
	}

	template <typename T>
	void AddParam(string &&name, T &&value)
	{
		if constexpr (std::is_arithmetic_v<T>)
			m_RequestParams.emplace_back(make_pair(name, to_string(value)));
		else
			m_RequestParams.emplace_back(make_pair(name, value));
	}

	void SyncSend()
	{
		m_Conn->m_Packer->BeginPack();
		for (const auto &item : m_RequestParams)
			m_Conn->m_Packer->AddField(item.first.c_str(), 'S', item.second.length());

		for (const auto &item : m_RequestParams)
			m_Conn->m_Packer->AddStr(item.second.c_str());

		m_Conn->m_Packer->EndPack();

		int ret = m_Conn->m_Connection->SendBiz(m_FuncId, m_Conn->m_Packer, 0, 0, 1);
		if (ret <= 0)
		{
			fmt::print("SendBiz return failed : {} = {}\n", ret, m_Conn->m_Connection->GetErrorMsg(ret));
		}

		IF2UnPacker *unPacker = nullptr;
		ret = m_Conn->m_Connection->RecvBiz(ret, (void **)&unPacker, 20 * 1000, 0);
		if (ret < 0)
		{
			fmt::print("RecvBiz failed : {} = {}\n", ret, m_Conn->m_Connection->GetErrorMsg(ret));
		}

		if (ret == 1) // 数据接收成功,但业务失败
		{
			fmt::print("Biz failed {} = {}\n", unPacker->GetInt("error_no"), unPacker->GetStr("error_info"));
		}
		else
		{
			ShowPacket(unPacker);
		}
	}

	void SendMsg()
	{
		m_Conn->m_Packer->BeginPack();
		for (const auto &item : m_RequestParams)
			m_Conn->m_Packer->AddField(item.first.c_str(), 'S', item.second.length());

		for (const auto &item : m_RequestParams)
			m_Conn->m_Packer->AddStr(item.second.c_str());
		m_Conn->m_Packer->EndPack();

		m_Conn->m_BizMsg->SetFunction(m_FuncId);
		m_Conn->m_BizMsg->SetPacketType(REQUEST_PACKET);
		m_Conn->m_BizMsg->SetContent(m_Conn->m_Packer->GetPackBuf(), m_Conn->m_Packer->GetPackLen());

		int ret = m_Conn->m_Connection->SendBizMsg(m_Conn->m_BizMsg, 1);
		if (ret <= 0)
		{
			fmt::print("SendBizMsg failed : {} = {}", ret, m_Conn->m_Connection->GetErrorMsg(ret));
		}
	}

private:
	Connection *m_Conn;
	vector<HsRequestParam> m_RequestParams;
	int m_FuncId = -1;
};